package cn.cloud.all.security.oauth2.provider;

import cn.cloud.all.security.core.GrantedAuthority;

import java.io.Serializable;
import java.util.*;

public class OAuth2Request extends BaseRequest implements Serializable {

    private static final long serialVersionUID = 1L;

    private Set<String> resourceIds = new HashSet<>();

    private Collection<? extends GrantedAuthority> authorities = new HashSet<>();

    private boolean approved = false;

    private TokenRequest refresh = null;

    private String redirectUri;

    private Set<String> responseTypes = new HashSet<>();

    private Map<String, Serializable> extensions = new HashMap<>();

    public OAuth2Request(Map<String, String> requestParameters, String clientId,
                         Collection<? extends GrantedAuthority> authorities, boolean approved, Set<String> scope,
                         Set<String> resourceIds, String redirectUri, Set<String> responseTypes,
                         Map<String, Serializable> extensionProperties) {

        setClientId(clientId);
        setRequestParameters(requestParameters);
        setScope(scope);
        if (resourceIds != null) {
            this.resourceIds = new HashSet<>(resourceIds);
        }
        if (authorities != null) {
            this.authorities = new HashSet<GrantedAuthority>(authorities);
        }
        this.approved = approved;
        if (responseTypes != null) {
            this.responseTypes = new HashSet<>(responseTypes);
        }
        this.redirectUri = redirectUri;
        if (extensionProperties != null) {
            this.extensions = extensionProperties;
        }
    }

    protected OAuth2Request(OAuth2Request other) {
        this(other.getRequestParameters(), other.getClientId(), other.getAuthorities(), other.isApproved(), other.getScope(), other.getResourceIds(), other.getRedirectUri(), other.getResponseTypes(), other.getExtensions());
    }

    protected OAuth2Request(String clientId) {
        setClientId(clientId);
    }

    protected OAuth2Request() {
        super();
    }

    public String getRedirectUri() {
        return redirectUri;
    }

    public Set<String> getResponseTypes() {
        return responseTypes;
    }

    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    public boolean isApproved() {
        return approved;
    }

    public Set<String> getResourceIds() {
        return resourceIds;
    }

    public Map<String, Serializable> getExtensions() {
        return extensions;
    }

    public OAuth2Request createOAuth2Request(Map<String, String> parameters) {
        return new OAuth2Request(parameters, getClientId(), authorities, approved, getScope(), resourceIds, redirectUri, responseTypes, extensions);
    }

    public OAuth2Request narrowScope(Set<String> scope) {
        OAuth2Request request = new OAuth2Request(getRequestParameters(), getClientId(), authorities, approved, scope, resourceIds, redirectUri, responseTypes, extensions);
        request.refresh = this.refresh;
        return request;
    }

    public OAuth2Request refresh(TokenRequest tokenRequest) {
        OAuth2Request request = new OAuth2Request(getRequestParameters(), getClientId(), authorities, approved, getScope(), resourceIds, redirectUri, responseTypes, extensions);
        request.refresh = tokenRequest;
        return request;
    }

    public boolean isRefresh() {
        return refresh != null;
    }

    public String getGrantType() {
        if (getRequestParameters().containsKey("grant_type")) {
            return getRequestParameters().get("grant_type");
        }
        if (getRequestParameters().containsKey("response_type")) {
            String response = getRequestParameters().get("response_type");
            if (response.contains("token")) {
                return "implicit";
            }
        }
        return null;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result + (approved ? 1231 : 1237);
        result = prime * result + ((authorities == null) ? 0 : authorities.hashCode());
        result = prime * result + ((extensions == null) ? 0 : extensions.hashCode());
        result = prime * result + ((redirectUri == null) ? 0 : redirectUri.hashCode());
        result = prime * result + ((resourceIds == null) ? 0 : resourceIds.hashCode());
        result = prime * result + ((responseTypes == null) ? 0 : responseTypes.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (!super.equals(obj))
            return false;
        if (getClass() != obj.getClass())
            return false;
        OAuth2Request other = (OAuth2Request) obj;
        if (approved != other.approved)
            return false;
        if (authorities == null) {
            if (other.authorities != null)
                return false;
        } else if (!authorities.equals(other.authorities))
            return false;
        if (extensions == null) {
            if (other.extensions != null)
                return false;
        } else if (!extensions.equals(other.extensions))
            return false;
        if (redirectUri == null) {
            if (other.redirectUri != null)
                return false;
        } else if (!redirectUri.equals(other.redirectUri))
            return false;
        if (resourceIds == null) {
            if (other.resourceIds != null)
                return false;
        } else if (!resourceIds.equals(other.resourceIds))
            return false;
        if (responseTypes == null) {
            return other.responseTypes == null;
        } else return responseTypes.equals(other.responseTypes);
    }
}
